/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "stdio.h"
#include "string.h"
#include "cmsis_os2.h"
#include "iot_uart.h"
#include "iot_errno.h"
#include "session.h"
#include "softbus_common.h"
#include "trans_uart_485.h"

#define TASK_STACK_SIZE         1024*4                //任务栈大小
#define TASK_PRIO               20 
#define IOT_UART_IDX            1
#define BUFF_SIZE               100
#define DATA_SIZE               128
#define HEADER_SIZE             5

#define RS485_INIT      1
#define RS485_WRITE     2
#define RS485_READ      3
#define RS485_DEINIT    4

#define RS485_REPLY_MESSAGE    1
#define RS485_REPLY_DATA       2

#define RS485_INIT_SUCCESS      1
#define RS485_WRITE_SUCCESS     2
#define RS485_READ_SUCCESS      3
#define RS485_DEINIT_SUCCESS    4
#define RS485_INIT_FAIL         5
#define RS485_HEADER_WORNG      6
#define RS485_CRC_WORNG         7

#define PKG_NAME "com.huawei.dmsdp"

const char *g_sessionName_uart_485 = "com.huawei.dmsdp.transmission_UART_485";

//L2请求L0数据包结构体
typedef struct _RS485_data
{
    char header[HEADER_SIZE];     //"AABB"
    uint8_t cmd;        //命令 1 init  2 write  3 read  4 deinit 5 6 7 8 
    uint8_t serial;     //485串口号
    uint8_t data_num;   //问询帧包含的数据个数，数据以16进制输入
    unsigned char message[BUFF_SIZE];   //问询指令
    uint16_t crc;       //校验位
} RS485_data;

//L0回复L2数据包结构体
typedef struct _RS485_reply_data
{
    char reply_header[HEADER_SIZE];         //"BBAA"
    uint8_t type;           //回复包类型：1 RS485_REPLY_MESSAGE 消息 2 RS485_REPLY_DATA 数据
    uint8_t reply_message; // 1 init success 2 write success 3 read success 4 deinit success 5 init fail
    uint8_t reply_data_num; //回复的数据个数
    unsigned char reply_data[BUFF_SIZE];//回复的数据
    uint16_t reply_crc;       //校验位
} RS485_reply_data;

uint16_t DoBrcBak(unsigned char *ptr, int len)
{
    unsigned int i;
    uint16_t crc = 0xFFFF;  //crc16位寄存器初始值

    while(len--)
    {
        crc ^= *ptr++;
        for (i = 0; i < 8; ++i)
        {
            if (crc & 1)
                crc = (crc >> 1) ^ 0xA001; //多项式 POLY（0x8005)的高低位交换值，这是由于其模型的一些参数决定的
            else
                crc = (crc >> 1);
        }
    }

    return crc;
}

int OnSessionOpenedUart485(int sessionId, int result)
{
    printf("\n>>>OnSession_UART_485_Opened sessionId = %d, result = %d.\n", sessionId, result);
    return 0;
}

void OnSessionClosedUart485(int sessionId)
{
    printf("\n>>>OnSession_UART_485_Closed sessionId = %d.\n", sessionId);
}

void OnBytesReceivedUart485(int sessionId, const void *data, unsigned int dataLen)
{
    printf("\n>>>OnBytes_UART_485_Received sessionId = %d, data = %s.\n", sessionId, data);
}

//L0给L2回复的模板函数
void ReplyMessageBak(int sessionId, const void * reply, uint8_t message)
{
    RS485_reply_data *data_prm = (RS485_reply_data *)reply;

    data_prm->type = RS485_REPLY_MESSAGE;
    data_prm->reply_message = message;
    data_prm->reply_data_num = 0;
    strcpy(data_prm->reply_header, "BBAA\0");
    data_prm->reply_crc = DoBrcBak(data_prm,sizeof(data_prm));

    printf("this is test for reply_message = %d \n",data_prm->reply_message);
    printf("\r\n");

    int ret = SendMessage(sessionId, (void *)data_prm, sizeof(RS485_reply_data));

    if (ret != 0) {
        printf("SendMessage fail, ret = %d\n", ret);
    } else {
        printf("SendMessage ok\n");
    }
    return;
}

void OnMessageReceivedUart485(int sessionId, const void *data, unsigned int dataLen)
{
    printf("\n>>>OnMessage_485_Received sessionId = %d, data = %p \n", sessionId, data);
    uint8_t datar_num;
    RS485_data *data_pr = (RS485_data *)data;
    uint16_t crc;

    RS485_reply_data *data_p = (RS485_reply_data *)malloc(sizeof(RS485_reply_data));
    if (data_p == NULL) {
        return;
    }
    
    printf("\nrecvdata_p->cmd:%d", data_pr->cmd);
    printf("\nrecvdata_p->serial:%d", data_pr->serial);

    char header_check[HEADER_SIZE] = {"AABB"};
    if (!strcmp(data_pr->header, header_check))
    {
        printf("\nheader is correct ");
    } else {
        printf("\nheader is not correct ");
        printf("\r\n");
        ReplyMessageBak(sessionId, data_p, RS485_HEADER_WORNG);
        free(data_p);
        data_p = NULL;
        return;
    }

    crc = DoBrcBak(data_pr,sizeof(data_pr));
    if (crc != data_pr->crc)
    {
        printf("\ncrc is not correct ");
        printf("\r\n");
        ReplyMessageBak(sessionId, data_p, RS485_CRC_WORNG);
        free(data_p);
        data_p = NULL;
        return;
    } else {
        printf("\ncrc is correct \n");
    }

    int ret;
    uint8_t uart_buff[BUFF_SIZE] = {0};
    uint8_t *uart_buff_p = uart_buff;

    //透传L2发来的指令
    if(data_pr->cmd == RS485_INIT)
    {
        IotUartAttribute uart_attr = {
            .baudRate = 9600,
            .dataBits = 8,
            .stopBits =1,
            .parity = 0,
        };
        //初始化UART driver
        if(IoTUartDeinit(data_pr->serial) != IOT_SUCCESS)
        {
            printf("Deinit before init FAILED\n");
            return;
        }
        ret = IoTUartInit(data_pr->serial,&uart_attr);
        if (ret != IOT_SUCCESS)
        {
            printf("Init Uart Falied Error No : %d\n",ret);
            ReplyMessageBak(sessionId, data_p, RS485_INIT_FAIL);
        } else {
            printf("Init Uart Success No : %d\n",ret);
            //设置L0给L2的回复数据
            ReplyMessageBak(sessionId, data_p, RS485_INIT_SUCCESS);
        }
    }
    else if(data_pr->cmd == RS485_WRITE) 
    {
        datar_num = data_pr->data_num;
        printf("recvdata_p->data_num:%d\n", datar_num);

        //保存收到的查询指令
        printf("save message ...\n");
        for(int j = 0; j < datar_num; j++){
            data_pr->message[j] = ((RS485_data *)data)->message[j];
        }

        ret = IoTUartWrite(data_pr->serial,data_pr->message,datar_num);
        //打印问询的指令
        printf("size of message is : %d \n",datar_num);
        printf("write: ");
        for(int j = 0; j < datar_num; j++){
            printf("%x  ", data_pr->message[j]);
        }
        printf("\r\n");
        printf("Uart Test write success!!!\n");

        //设置回复报文
        ReplyMessageBak(sessionId, data_p, RS485_WRITE_SUCCESS);
    }
    else if(data_pr->cmd == RS485_READ) 
    {   //还要加上返回给L2的消息
        printf("Uart into read!!!\n");
        data_p->reply_data_num = IoTUartRead(data_pr->serial,uart_buff_p,BUFF_SIZE);
        if (data_p->reply_data_num < 0 || data_p->reply_data_num > BUFF_SIZE) {
            printf("UartRead: read data failed, ret %d\n", data_p->reply_data_num);
            free(data_p);
            data_p = NULL;
            return;
        }
        //打印采集到的信息
        printf("read: ");
        for(int j = 0; j < data_p->reply_data_num; j++){
            printf("%x  ", uart_buff[j]);
        }
        printf("\r\n");
        printf("Uart after read!!!\n");

        //设置回复报文
        data_p->type = RS485_REPLY_DATA;
        for(uint8_t i = 0; i < data_p->reply_data_num; i++)
        {
            data_p->reply_data[i] = uart_buff[i];
        }
        data_p->reply_message = RS485_READ_SUCCESS;
        strcpy(data_p->reply_header, "BBAA\0");
        data_p->reply_crc = DoBrcBak(data_p,sizeof(data_p));

        // ReplyMessageBak(sessionId,data_p);
        int ret = SendMessage(sessionId, (void *)data_p, sizeof(RS485_reply_data));

        if (ret != 0) {
            printf("SendMessage fail 2, ret = %d\n", ret);
        } else {
            printf("SendMessage ok\n");
        }
    } 
    else if(data_pr->cmd == RS485_DEINIT) 
    {
        ret = IoTUartDeinit(data_pr->serial);
        if(ret != IOT_SUCCESS){
            printf("uart deinit fail\r\n");
            return;
        }else{
            printf("uart deinit success\r\n");
            //设置回复报文
            ReplyMessageBak(sessionId, data_p, RS485_DEINIT_SUCCESS);
        }
    } 
    else
    {
        printf("SendMessage not right\n"); 
    }
    free(data_p);
    data_p = NULL;
    return;
}

void T_CreateSessionServerUart485(void)
{
    ISessionListener listener = {
        .OnSessionOpened = OnSessionOpenedUart485,
        .OnSessionClosed = OnSessionClosedUart485,
        .OnBytesReceived = OnBytesReceivedUart485,
        .OnMessageReceived = OnMessageReceivedUart485,
        .OnStreamReceived = NULL,
        .OnQosEvent = NULL
    };

    int ret = CreateSessionServer(PKG_NAME, g_sessionName_uart_485, &listener);
    if (ret != 0) {
        printf("CreateSessionServer fail, ret = %d.\n", ret);
        return;
    }
    printf("CreateSessionServer ok.\n");
}

void T_RemoveSessionServerUart485(void)
{
    int ret = RemoveSessionServer(PKG_NAME, g_sessionName_uart_485);
    if (ret != 0) {
        printf("RemoveSessionServer fail, ret = %d.\n", ret);
        return;
    }
    printf("RemoveSessionServer ok.\n");
}

